#include "../card.h"
#include "device.h"
#include "card_nxp520.h"
#include "../card_crypto.h"

/* 调试打印接口 */
#define CARD_LOG(format, ...)     OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)
#define __CARD_LOG(format, ...)   //__OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)

/* 虚拟硬件接口 */
#define VHW_ADC_CARD vADC_2
#define VHW_IRQ_CARD vPIN_I4

/* 读卡事件 */
#define EVENT_READ_CARD (0X00000001)

/* 天线环境值更新系数 */
#define ANT_UPDATE_FACTOR (3)

/* ADC卡片侦测阀值 */
#if defined(CARD_SIZE_BIG) //大卡片
#define ANT_THRESHOLD_RATIO (0.12f) //TODO，待调试
#else
#define ANT_THRESHOLD_RATIO (0.12f)
#endif

#define NFC_LPCD //17580才支持LPCD

/* 无卡时的天线信号（环境值） */
__NVRAM static uint16_t noCardAntennaSignal = 0;

/* 卡片工作模式 */
static CardMode_enum_t card_mode = CARD_MODE_VERIFY;

__EFRAM static FunctionalState card_func = ENABLE;

/**
  * @brief  ADC卡片侦测，更新环境值
  * @note   当连续多次天线信号值都是偏差不大，就更新一次环境值（无卡时的天线信号）
  *         
  * @param  antennaSignal：当前的天线信号
  */
static void Card_DetectUpdate(uint16_t antennaSignal)
{
	__NVRAM static uint16_t lastValue;	 //上次天线信号
	__NVRAM static uint8_t antennaTrend; //天线变化趋势

	antennaTrend <<= 1;
	antennaTrend |= (abs(antennaSignal - lastValue) < 10) ? 1 : 0;
	if ((antennaTrend & ~(0XFFFFFFFF << ANT_UPDATE_FACTOR)) == ~(0XFFFFFFFF << ANT_UPDATE_FACTOR) || (noCardAntennaSignal == 0))
	{
		if (noCardAntennaSignal == 0)
		{
			noCardAntennaSignal = antennaSignal;
		}
		else
		{
			noCardAntennaSignal = (noCardAntennaSignal + antennaSignal) >> 1;
		}
		__CARD_LOG("NoCardAntennaSignal:%d\r\n\r\n", noCardAntennaSignal);
	}
	lastValue = antennaSignal;
}

/**
  * @brief  检测是否有卡片靠近
  *
  * @param  antennaSignal：当前的天线信号
  *
  * @return ADC侦测有卡返回SUCCESS，否则返回ERROR
  */
static ErrorStatus Card_AdcDetect(uint16_t antennaSignal)
{
	uint16_t adc_threshold = (uint16_t)((float)(noCardAntennaSignal) * ANT_THRESHOLD_RATIO);
	__CARD_LOG("AntennaSignal:%d,  threshold:%d,  offset:%d\r\n", antennaSignal, adc_threshold, noCardAntennaSignal - antennaSignal);
	if ((int)(noCardAntennaSignal - antennaSignal) >= adc_threshold)
	{
		CARD_LOG("Adc detect success\r\n");
		return SUCCESS;
	}
	return ERROR;
}

/**
  * @brief  处理验证卡片、添加卡片
  * @note   验证卡片是否合法
  *         
  * @param  type：卡片类型
  * @param  pID：卡片ID号
  * @param  len：ID号长度
  * 
  * @return SUCCESS/ERROR
  */
static ErrorStatus Card_ProcessVerifyOrAddCard(uint8_t type, uint8_t *pID, uint8_t len, uint8_t *err)
{
	if (card_mode == CARD_MODE_VERIFY) //验证卡片
	{
		/* 读ID成功：验证卡片是否合法  */
		if (CardCrypto_VerifyCard(pID, len, type, err) != ERROR)
		{
			CARD_LOG("verify success\r\n");
			return SUCCESS;
		}
		CARD_LOG("verify failed\r\n");
	}
	else if (card_mode == CARD_MODE_ADD) //添加卡片
	{
		/* 读ID成功：执行卡片添加流程  */
		if (CardCrypto_AddCard(pID, len, type) != ERROR)
		{
			CARD_LOG("add success\r\n");
			return SUCCESS;
		}
		CARD_LOG("add failed\r\n");
	}
	return ERROR;
}

#ifdef NFC_LPCD
//============================================================================
#define JREG_LPCD_CTRL0 0x3C //Lpcd Ctrl register0
//============================================================================
#define JBIT_LPCD_IRQ_INV 0x20		//
#define JBIT_LPCD_IRQ_PUSHPULL 0x10 //
#define LPCD_DISABLE 0x00
#define LPCD_RAPID_5us 0x01	  //
#define LPCD_RAPID_10us 0x02  //
#define LPCD_RAPID_20us 0x03  //
#define LPCD_RAPID_40us 0x04  //
#define LPCD_RAPID_80us 0x05  //
#define LPCD_RAPID_160us 0x06 //
#define LPCD_RAPID_320us 0x07 //
//============================================================================

//============================================================================
#define JREG_LPCD_CTRL1 0x3D //Lpcd Ctrl register1
//============================================================================
#define JBIT_LPCD_TX2_EN 0x20	  //
#define JBIT_LPCD_TX1_EN 0X10	  //
#define JBIT_LPCD_TX2_INV_ON 0x08 //
#define JBIT_LPCD_TX1_INV_ON 0x04 //
// #define		JBIT_LPCD_TX2_INV_OFF		0x02	//
// #define		JBIT_LPCD_TX1_INV_OFF			0x01	//
//============================================================================
#define JREG_LPCD_CTRL2 0x3E //Lpcd Ctrl register2
//============================================================================

//============================================================================
#define JREG_LPCD_CTRL3 0x3F //Lpcd Ctrl register3
//============================================================================
#define JBIT_LPCD_TOUT_PIN 0x20 //
#define JBIT_LPCD_IRQ_PIN 0x10	//
//============================================================================

//============================================================================
#define JREG_LPCD_CTRL4 0x04 //Lpcd Ctrl register4
//============================================================================

//============================================================================
#define JREG_EXT_REG_ENTRANCE 0x0F //ext register entrance
//============================================================================
#define JBIT_EXT_REG_WR_ADDR 0x40 //wrire address cycle
#define JBIT_EXT_REG_RD_ADDR 0x80 //read address cycle
#define JBIT_EXT_REG_WR_DATA 0xC0 //write data cycle
#define JBIT_EXT_REG_RD_DATA 0x00 //read data cycle

#define LPCD_CWP 63 //LPCD PMOS输出驱动 0~63
#define LPCD_CWN 15 //LPCD NMOS输出驱动 0~15

//***********************************************
//函数名称：SetReg_Ext(unsigned char ExtRegAddr,unsigned char* ExtRegData)
//函数功能：写扩展寄存器
//入口参数：ExtRegAddr:扩展寄存器地址   ExtRegData:要写入的值
//出口参数：unsigned char  TRUE：写成功   FALSE:写失败
//***********************************************
void SetReg_Ext(unsigned char ExtRegAddr, unsigned char ExtRegData)
{
	Nxp520_Write_Reg(JREG_EXT_REG_ENTRANCE, JBIT_EXT_REG_WR_ADDR + ExtRegAddr);
	Nxp520_Write_Reg(JREG_EXT_REG_ENTRANCE, JBIT_EXT_REG_WR_DATA + ExtRegData);
	return;
}

static void Lpcd_Init_Register(void)
{
	MF_NRST_H; //NPD=1
	Device_DelayUs(500);
	Device_DelayUs(500);
	SetReg_Ext(JREG_LPCD_CTRL0, JBIT_LPCD_IRQ_PUSHPULL | LPCD_RAPID_10us);
	SetReg_Ext(JREG_LPCD_CTRL1, JBIT_LPCD_TX2_EN | JBIT_LPCD_TX2_INV_ON); //|JBIT_LPCD_TX1_EN|JBIT_LPCD_TX2_INV_ON);
	SetReg_Ext(JREG_LPCD_CTRL2, LPCD_CWP);								  //LPCD_CWP 0~63
	SetReg_Ext(JREG_LPCD_CTRL3, JBIT_LPCD_IRQ_PIN | LPCD_CWN);			  //LPCD_CWN 0~15
	MF_NRST_L;
}
#endif

/**
  * @brief  读取卡片ID 
  * @note   
  *         
  * @param  pID：id缓存区，必须大于10byte
  * @return 无卡返回0，非法卡返回1，正常返回卡号长度（4/7/10）
  */
static uint8_t Card_ReadCardId(uint8_t *pID, uint8_t crypto, FlagStatus sleep)
{
	if (card_func == DISABLE) //无刷卡功能
	{
		return 0;
	}
	uint8_t len = 0;
	uint8_t cardType;
	uint16_t adcValue;
	uint32_t timeOut = 100;
	__EFRAM static uint8_t flag = 1;

#ifdef NFC_LPCD
	if (flag)
	{
		flag = 0;
        Device_Enable(VHW_SPI_CARD);
		Lpcd_Init_Register();
		return 0;
	}
#endif

	/* 开一下读卡器天线，ADC采集天线信号 */
	Device_EnterCritical();
	MF_NRST_H;

	Device_Enable(VHW_ADC_CARD);
    
#ifdef NFC_LPCD
	uint8_t irq_value = 0;
    timeOut = 300;
    do
	{
		irq_value = (uint8_t)Device_Read(VHW_IRQ_CARD, NULL, 0, 0);
	} while (irq_value == 0 && timeOut--);
    Device_DelayUs(6);
#else
	Device_DelayUs(200);
	do
	{
		if (Nxp520_Read_Reg(CommandReg) == 0x20)
		{
			Nxp520_Write_Reg(TxControlReg, ANT_TX2);
			break;
		}
	} while (--timeOut); //timeout设置为100，超时时间约为1.1ms
	Device_DelayUs(10);
#endif
	MF_NRST_L;

	adcValue = (uint16_t)Device_Read(VHW_ADC_CARD, NULL, 0, 0);
	Device_ExitCritical();

	/* 判断是否有卡 */
	if (Card_AdcDetect(adcValue) == SUCCESS)
	{
        Device_Write(vCAP_SENSE0, NULL, 0, 0);//关闭触摸
        Device_Enable(VHW_SPI_CARD);
		Nxp520_Reset();
		#ifdef NFC_LPCD
		if(irq_value)//判断一下 LPCD是否出中断  没出中断说明有问题  不启动读卡流程
		#endif
		{
			len = CardCrypto_ReadCardId(pID, &cardType); //读卡类型和卡ID
			if (len != 0)
			{
				CARD_LOG("Read card id succeed\r\n");
				if (crypto != 0)
				{
					uint8_t err = 0;
					if (Card_ProcessVerifyOrAddCard(cardType, pID, len, &err) != SUCCESS) //加密信息验证或者添加卡片
					{
						len |= 0X80;								//非法卡、添加失败：将len的bit7设置为1
						len |= (err == CARD_ERR_NO_ADD) ? 0X40 : 0; //合法卡片但未添加
					}
				}
			}
		}
#ifdef NFC_LPCD
		Lpcd_Init_Register();
#endif
		MF_NRST_L;
        if (sleep == SET)
        {
            Device_Disable(VHW_SPI_CARD); //休眠状态下读卡结束要关闭SPI
        }
        Device_Write(vCAP_SENSE0, NULL, 0, 2);//开启触摸
	}

	/* 读ID失败：更新无卡时的环境值 */
	if (len == 0)
	{
		Card_DetectUpdate(adcValue);
	}
	return len;
}

/**
  * @brief  读取卡片ID
  *         
  * @note   设计防重复读卡逻辑，将读取到的卡片ID发给订阅者
  */
static uint8_t Card_ReadID(void)
{
	static uint8_t count = 0;
	static FlagStatus activeFlag = RESET;
	CardMsg_t msg;

	memset((uint8_t *)&msg, 0x00, sizeof(CardMsg_t));
	
#ifndef CARD_CRYPTO_DISABLE
	msg.cardLen = Card_ReadCardId(msg.cardId, 1, RESET);
#else
	msg.cardLen = Card_ReadCardId(msg.cardId, 0, RESET);
#endif
	if (msg.cardLen > 0)
	{
		CARD_LOG("Card len:%#X,  id:%02X %02X %02X %02X\r\n", msg.cardLen, msg.cardId[0], msg.cardId[1], msg.cardId[2], msg.cardId[3]);
		if (activeFlag != SET)
		{
			activeFlag = SET;
			OSAL_MessagePublish(&msg, sizeof(CardMsg_t));
		}
		count = 0;
	}
	else
	{
		if (activeFlag != RESET)
		{
			if (++count >= 3)
			{
				activeFlag = RESET;
				OSAL_MessagePublish(&msg, sizeof(CardMsg_t));
			}
		}
	}
	return msg.cardLen;
}

/**
 * @brief  卡片定时唤醒回调
 *
 * @param  mode：模式
 * @return 
 */
static int32_t Card_TimedWakeupHandle(uint32_t dev)
{
    uint8_t cardId[10] = {0};
	int32_t aa = (int32_t)Card_ReadCardId(cardId, 0, SET);//休眠状态下扫卡
    return aa;
}

/**
 * @brief  设置卡片模式
 *
 * @param  mode：模式
 * @return 
 */
static ErrorStatus Card_SetWorkMode(CardMode_enum_t mode)
{
	card_mode = mode;
	return SUCCESS;
}

/**
 * @brief  设置卡片功能开关
 *
 * @param  func：功能
 * @return 
 */
static ErrorStatus Card_SetFunction(FunctionalState status)
{
	card_func = status;
	return SUCCESS;
}

static void Card_SelfTest(void)
{
	/* 自检，读取某个寄存器值，判断是否正常 */
	uint16_t timeOut = 200;
	do
	{
		if (Nxp520_Read_Reg(CommandReg) == 0x20)
		{
			break;
		}
	} while (--timeOut);
	OSAL_MessagePublishErrorCode(ERRCODE_TYPE_NFC, (timeOut == 0) ? 1 : 0);
}

static void Card_Init(void)
{
	/* 读卡器接口初始化 */
	Nxp520_Portinit();

	/* ADC检卡初始化 */
	Device_Enable(VHW_ADC_CARD);

	/* 自检 */
	Card_SelfTest();

	/* 配置休眠 */
	MF_NRST_L;
}

/**
  * @brief  卡片任务函数
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Card_Task(uint32_t event)
{
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
		CARD_LOG("Card task start\r\n");
		Card_Init();
		OSAL_EventSingleCreate(COMP_CARD, EVENT_READ_CARD, 1, EVT_PRIORITY_LOW);

		SYS_API(Card_SetWorkMode);
		SYS_API(Card_SetFunction);
		return (event ^ EVENT_SYS_START);
	}

	/* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
		OSAL_EventDelete(COMP_CARD, EVENT_READ_CARD);
        Device_Disable(VHW_SPI_CARD);
		CARD_LOG("Card task sleep\r\n");
		return (event ^ EVENT_SYS_SLEEP);
	}

	/* 读卡事件 */
	if (event & EVENT_READ_CARD)
	{
		Card_ReadID();
		OSAL_EventSingleCreate(COMP_CARD, EVENT_READ_CARD, 100, EVT_PRIORITY_LOW);
		return (event ^ EVENT_READ_CARD);
	}
	return 0;
}
COMPONENT_TASK_EXPORT(COMP_CARD, Card_Task, 16);
COMPONENT_WAKEUP_EXPORT(COMP_CARD, Card_TimedWakeupHandle, vTIMER_1); 
